using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Koda.VisualStudio.Integration;
using Koda.UI;
using Koda.Utils;
using Koda.Search;
using Koda.Search.Finders;
using EnvDTE;
using EnvDTE80;
using Koda.Model;
using Koda.VisualStudio;

namespace Koda.Commands
{
    public class SortMembersCommand : VsCommand
    {
        public SortMembersCommand()
            : base("Sort members", "Code Window", 1)
        {
        }

        public override bool OnQueryStatus(VsCommandEventArgs e)
        {
            if (VsCodeModelUtilities.GetClassFromSelection(e.DTE) != null)
                return true;
            return false;
        }

        public override void OnExecute(VsCommandEventArgs e)
        {
            CodeClass2 codeClass = VsCodeModelUtilities.GetClassFromSelection(e.DTE);
            if (codeClass != null)
            {
                SortMembers(codeClass);
            }
        }

        private void SortMembers(CodeClass2 codeClass)
        {
            DTE dte = codeClass.DTE;

            try
            {
                dte.UndoContext.Open("Sort Members", false);

                List<CodeElement2> codeElements = new List<CodeElement2>();
                foreach (CodeElement codeElement in codeClass.Members)
                {
                    codeElements.Add((CodeElement2)codeElement);
                }

                if (codeElements.Count > 1)
                {
                    codeElements.Sort(new CodeElementComparer());

                    StringBuilder sb = new StringBuilder();
                    TextSelection ts = (TextSelection)dte.ActiveDocument.Selection;
                    TextDocument td = (TextDocument)dte.ActiveDocument.Object("TextDocument");
                    EditPoint2 ep = (EditPoint2)td.StartPoint.CreateEditPoint();

                    //get text
                    for (int i = 0; i < codeElements.Count; i++)
                    {
                        CodeElement2 codeElement = codeElements[i];
                                                
                        ep.MoveToPoint(GetStartPoint(codeElement));
                        string text = ep.GetText(codeElement.EndPoint).Trim();

                        if (i > 0)
                        {
                            sb.Append(Environment.NewLine);
                            if (codeElements[i - 1].Kind == vsCMElement.vsCMElementVariable && codeElement.Kind != vsCMElement.vsCMElementVariable)
                            {
                                sb.Append(Environment.NewLine);
                            }
                            else if (codeElements[i - 1].Kind != vsCMElement.vsCMElementVariable)
                            {
                                sb.Append(Environment.NewLine);
                            }
                        }

                        sb.Append(text);
                    }

                    //delete codeelements
                    foreach(CodeElement2 codeElement in codeElements)
                    {
                        ep.MoveToPoint(GetStartPoint(codeElement));
                        ep.Delete(codeElement.EndPoint);
                    }

                    //insert text
                    ep.MoveToPoint(codeClass.GetStartPoint(vsCMPart.vsCMPartBody));
                    string t = sb.ToString();
                    ep.Insert(t);

                    ep.MoveToPoint(codeClass.StartPoint);
                    ep.SmartFormat(codeClass.EndPoint);
                }
            }
            catch (Exception)
            {
                dte.UndoContext.SetAborted();
                throw;
            }
            finally
            {
                if (dte.UndoContext.IsOpen)
                {
                    dte.UndoContext.Close();
                }
            }
        }

        private TextPoint GetStartPoint(CodeElement codeElement)
        {
            TextPoint textPoint = codeElement.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes);
            EditPoint2 editPoint = (EditPoint2)textPoint.CreateEditPoint();

            while (true)
            {
                editPoint.LineUp(1);
                editPoint.StartOfLine();
                
                string text = editPoint.GetText(editPoint.LineLength).Trim();
                if (text == String.Empty || text.StartsWith("//")) //FIXME: Won't work with VB
                {
                    textPoint = editPoint.CreateEditPoint();
                }
                else
                {
                    break;
                }
            }
           
            return textPoint;
        }



    }
}
